// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#include "coin2/exchange/bithumb/api_util/auth_key.h"

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

#include "coin2/base/base64.h"
#include "coin2/base/time.h"
#include "coin2/exchange/base/api_util/api_signature.h"
#include "coin2/exchange/base/api_util/json_writer.h"

std::string BithumbBaseAuth::GetCurrTimeSeconds() {
  return std::to_string(GetCurrentTimestamp() / 1000000);
}

std::string BithumbBaseAuth::GetSignature(
    const std::string& secret_key,
    const std::string& address,
    const std::string& timestamp,
    const std::string& request_body) {
  if (secret_key.empty()) {
    throw std::runtime_error("[bithumb] secret key is empty");
  }
  char c = static_cast<char>(1);
  std::string separate(1, c);
  std::string cre = address + separate + request_body + separate + timestamp;
  std::string hash_str = ApiSignatureUtil::GetSignatureByHexHmacSHA512(cre, secret_key);
  return impl::base64_encode((unsigned char*)hash_str.c_str(), 128);
}

std::vector<std::pair<std::string, std::string>> BithumbRestAuth::GetHeaderSet(
    const std::string& address,
    const std::string& param) const {
  std::vector<std::pair<std::string, std::string>> out;
  std::string ts_str = GetCurrTimeSeconds();

  std::string signa = GetSignature(key_.secret_key(), address, ts_str, param);
  out.push_back(std::make_pair("Api-Key", key_.access_key()));
  out.push_back(std::make_pair("Api-Sign", signa));
  out.push_back(std::make_pair("Api-Nonce", ts_str));
  out.push_back(std::make_pair("api-client-type", "1"));
  if (!param.empty()) {
    out.push_back(std::make_pair("Content-Type", "application/x-www-form-urlencoded"));
  }
  return out;
}

AsioHttpContext* BithumbRestAuth::CreateRequestByPostWithSignature(
    const std::string& address,
    UrlParamsBuilder* builder) {
  std::string query_string = builder->ComputeQueryString();
  std::string post_body = builder->ComputePostBodyAsQueryString();
  std::string target = address;
  if (!query_string.empty()) {
    target += "?" + query_string;
  }
  if (!post_body.empty()) {
    post_body = ApiSignatureUtil::UrlEncode("endpoint=" + address + "&" + post_body);
  } else {
    post_body = ApiSignatureUtil::UrlEncode("endpoint=" + address);
  }
  return AsioHttpContext::NewPost(
      host_,
      port_,
      bind_ip_,
      target,
      GetHeaderSet(target, post_body),
      post_body);
}
